#ifndef IMAGEDISPLAY_H
#define IMAGEDISPLAY_H
#include <QMutex>
#include <QWidget>
#include <QSize>
#include <QSet>
#include <QAbstractVideoSurface>

class ImageMonitor;

class ImageView : public QWidget/*, public QAbstractVideoSurface*/
{
    Q_OBJECT
public:
//    QList<QVideoFrame::PixelFormat> supportedPixelFormats(
//            QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const Q_DECL_OVERRIDE;

    enum ImageFormat {RGB24, RGB32};
    explicit ImageView(ImageFormat format = RGB24, QWidget *parent = 0);
    ~ImageView();
    /**
    * @brief 将当前图像填充为单一颜色
    * @param cl 填充的颜色
    */	
    void fillImage(QRgb cl);
    /**
    * @brief 将当前图像填充为单一颜色
    * @param color 填充的颜色
    */	
    void fillImage(const QColor color);
    /**
    * @brief 将当前图像填充为单一颜色
    * @param color 填充的颜色
    */		
    void fillImage(Qt::GlobalColor color);

    /**
    * @brief 加载文件中的图像
    * @param fileName 带路径的完整文件名
    * @return true 表示加载成功，false 表示加载失败
    */	
    bool loadImage(const QString &fileName);
    /**
     * @brief saveImage 将图像保存到文件中
     * @param fileName 带路径的完整文件名
     * @return true 表示保存成功
     */
    bool saveImage(const QString &fileName);

    QSize sizeHint() const {return m_size * m_zoom_factor;}

    /**
     * @brief getImage 获取图像
     * @return
     */
    QImage getImage();
    /**
     * @brief getImageSize 获得图像的尺寸
     * @return
     */
    QSize getImageSize() const {return m_size;}

    /**
     * @brief setImageMonitor 每次更新图像时调用 monitor->imageChanged(QImage &image) 函数。
     * 用于自动对焦等需要实时计算的功能，//deleted考虑到不要对系统造成太大的负担，只能加载一个 monitor（观察者模式）
     * @param monitor
     */
    void setImageMonitor(ImageMonitor *monitor);
    /**
     * @brief removeImageMonitor 移除这个 monitor
     * @param monitor
     */
    void removeImageMonitor(ImageMonitor * monitor);
    /**
     * @brief removeAllImageMonitors 去掉所有的 monitor
     */
    void removeAllImageMonitors();

    /**
     * @brief setSize 设置图像尺寸
     * @param size
     */
    void setSize(QSize size);
protected:
    void paintEvent(QPaintEvent *event);
    void drawImage(QPainter &painter);
    void drawCross(QPainter &painter);
//    void mousePressEvent(QMouseEvent *event);
    void mouseDoubleClickEvent(QMouseEvent *event);
signals:
    /**
     * @brief mousePosition MousePositionPickMode 模式下，鼠标左键点击时输出鼠标的位置。
     * @param point
     */
    void mousePosition(QPoint &point);

    /**
     * @brief distance 输出鼠标距离中心点的距离
     * @param x
     * @param y
     */
    void distance(int x, int y);

    void zoomFactorPCTChanged(int factor);

public slots:
    void setVideoFrame(const QVideoFrame &frame);
    /**
     * @brief setRGB32Image 接收一个 RGB32类型的 QImage，更新界面。
     * @param image 这里要求这个 image 是 RGB32 /ARGB32 类型的。
     * 如果传入的类型不是 RGB32 类型的，则不处理。
     */
    void setRGB32Image(const QImage &image);
    /**
     * @brief setRGB24Image 接收一个 RGB24类型的 QImage，更新界面。
     * @param image 这里要求这个 image 是 RGB24 类型的。
     * 如果传入的类型不是 RGB24 类型的，则不处理。
     */
    void setRGB24Image(const QImage &image);
    /**
     * @brief setZoomFactor 设置图像的缩放系数，[0.01, 10.0]
     * @param factor
     */
    void setZoomFactor(double factor);
    /**
     * @brief setZoomFactor 设置图像的缩放系数，[1, 1000]
     * @param factor 以百分比计的缩放系数
     */
    void setZoomFactorPCT(int factor);
    /**
     * @brief showCross 是否在图像中心位置显示一个十字
     * @param show
     */
    void showCross(bool show);
    /**
     * @brief setMousePositionPickMode 是否实时输出鼠标位置，鼠标左键点击时输出
     * @param on
     */
    void setMousePositionPickMode(bool on);

protected:
    bool m_show_cross;
    double m_zoom_factor;

    QSize m_size;
	QImage m_image;

	QMutex m_image_mutex; ///< m_image 会被多个线程访问，需用 mutex 保护
    //ImageMonitor *m_image_monitor;
    bool m_mouse_pos_pick;

private:
    void imageChangedHook();
    void paintEventHook(QPainter &painter);
    void RGB32_to_RGB32(QImage &to, const QImage &from); /// 这里要求两个 image 都是 RGB32 或类似类型的。
    void RGB24_to_RGB32(QImage &to, const QImage &from);
    void RGB24_to_RGB24(QImage &to, const QImage &from);
    void RGB32_to_RGB24(QImage &to, const QImage &from);
    QSet<ImageMonitor *> m_monitor_set;

private slots:
//    bool present(const QVideoFrame &frame) override;

};

#endif // IMAGEDISPLAY_H
